bitkeeper revision 1.649 (3fdf2aeaeVXAAcKlXMdFTCQuwOYD_g)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 16 Dec 2003 15:55:22 +0000 (15:55 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 16 Dec 2003 15:55:22 +0000 (15:55 +0000)
xl_vbd.c, xl_block.h, xl_block.c:
  Fixes to Xenolinux blkdev code.

xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_block.c
xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_block.h
xenolinux-2.4.22-sparse/arch/xeno/drivers/block/xl_vbd.c

index 23f445515c83c1714ff77d873a7bc3a418d6a021..de71199c02806c45576787a7b29f5846fb9f41ee 100644 (file)
@@ -58,7 +58,7 @@ static inline void signal_requests_to_xen(void)
 
 static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
 {
-    struct gendisk *gd = xldev_to_gendisk(xldev);
+    struct gendisk *gd = get_gendisk(xldev);
     return (xl_disk_t *)gd->real_devices + 
         (MINOR(xldev) >> gd->minor_shift);
 }
@@ -67,26 +67,37 @@ static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
 int xenolinux_block_open(struct inode *inode, struct file *filep)
 {
     short xldev = inode->i_rdev; 
-    struct gendisk *gd = xldev_to_gendisk(xldev);
+    struct gendisk *gd = get_gendisk(xldev);
     xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
     short minor = MINOR(xldev); 
 
-    if(!gd->part[minor].nr_sects) { 
-       /* Device either doesn't exist, or has zero capacity; we use 
-          a few cheesy heuristics to return the relevant error code */
-       if(disk->capacity || (minor & (gd->max_p - 1))) { 
-           // we have a real device, but no such partition, or we just 
-           // have a partition number so guess this is the problem 
-           return -ENXIO;     // no such device or address 
-       } else if (gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE) {
-           // this is a removable device => assume that media is missing 
-           return -ENOMEDIUM; // media not present (this is a guess) 
-       } else 
-           // just go for the general 'no such device' error
-           return -ENODEV;    // no such device
+    if ( gd->part[minor].nr_sects == 0 )
+    { 
+        /*
+         * Device either doesn't exist, or has zero capacity; we use a few
+         * cheesy heuristics to return the relevant error code
+         */
+        if ( (gd->sizes[minor >> gd->minor_shift] != 0) ||
+             ((minor & (gd->max_p - 1)) != 0) )
+        { 
+            /*
+             * We have a real device, but no such partition, or we just have a
+             * partition number so guess this is the problem.
+             */
+            return -ENXIO;     /* no such device or address */
+        }
+        else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE )
+        {
+            /* This is a removable device => assume that media is missing. */ 
+            return -ENOMEDIUM; /* media not present (this is a guess) */
+        } 
+        else
+        { 
+            /* Just go for the general 'no such device' error. */
+            return -ENODEV;    /* no such device */
+        }
     }
 
-
     disk->usage++;
     DPRINTK("xenolinux_block_open\n");
     return 0;
@@ -103,7 +114,7 @@ int xenolinux_block_release(struct inode *inode, struct file *filep)
 
 
 int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
-                         unsigned command, unsigned long argument)
+                          unsigned command, unsigned long argument)
 {
     kdev_t dev = inode->i_rdev;
     struct hd_geometry *geo = (struct hd_geometry *)argument;
@@ -115,21 +126,21 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
     DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
                   command, (long) argument, dev); 
   
-    gd = xldev_to_gendisk(dev);
+    gd = get_gendisk(dev);
     part = &gd->part[MINOR(dev)]; 
 
     switch ( command )
     {
     case BLKGETSIZE:
         DPRINTK_IOCTL("   BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects); 
-       return put_user(part->nr_sects, (unsigned long *) argument);
+        return put_user(part->nr_sects, (unsigned long *) argument);
 
     case BLKRRPART:                               /* re-read partition table */
         DPRINTK_IOCTL("   BLKRRPART: %x\n", BLKRRPART); 
         return xenolinux_block_revalidate(dev);
 
     case BLKSSZGET:
-       return hardsect_size[MAJOR(dev)][MINOR(dev)]; 
+        return hardsect_size[MAJOR(dev)][MINOR(dev)]; 
 
     case BLKBSZGET:                                        /* get block size */
         DPRINTK_IOCTL("   BLKBSZGET: %x\n", BLKBSZGET);
@@ -137,35 +148,35 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
 
     case BLKBSZSET:                                        /* set block size */
         DPRINTK_IOCTL("   BLKBSZSET: %x\n", BLKBSZSET);
-       break;
+        break;
 
     case BLKRASET:                                         /* set read-ahead */
         DPRINTK_IOCTL("   BLKRASET: %x\n", BLKRASET);
-       break;
+        break;
 
     case BLKRAGET:                                         /* get read-ahead */
         DPRINTK_IOCTL("   BLKRAFET: %x\n", BLKRAGET);
-       break;
+        break;
 
     case HDIO_GETGEO:
         /* note: these values are complete garbage */
         DPRINTK_IOCTL("   HDIO_GETGEO: %x\n", HDIO_GETGEO);
-       if (!argument) return -EINVAL;
-       if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
-       if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
-       if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
-       if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
-       return 0;
+        if (!argument) return -EINVAL;
+        if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
+        if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
+        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+        if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
+        return 0;
 
     case HDIO_GETGEO_BIG: 
         /* note: these values are complete garbage */
         DPRINTK_IOCTL("   HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
-       if (!argument) return -EINVAL;
-       if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
-       if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
-       if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
-       if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
-       return 0;
+        if (!argument) return -EINVAL;
+        if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
+        if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
+        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+        if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+        return 0;
 
     case CDROMMULTISESSION:
         DPRINTK("FIXME: support multisession CDs later\n");
@@ -175,7 +186,7 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
 
     default:
         printk("ioctl %08x not supported by xl_block\n", command);
-       return -ENOSYS;
+        return -ENOSYS;
     }
     
     return 0;
@@ -190,13 +201,20 @@ int xenolinux_block_check(kdev_t dev)
 
 int xenolinux_block_revalidate(kdev_t dev)
 {
-    struct gendisk *gd = xldev_to_gendisk(dev);
+    struct gendisk *gd = get_gendisk(dev);
     xl_disk_t *disk = xldev_to_xldisk(dev);
-    unsigned long flags;
+    unsigned long flags, capacity = gd->part[MINOR(dev)].nr_sects;
     int i, disk_nr = MINOR(dev) >> gd->minor_shift; 
     
     DPRINTK("xenolinux_block_revalidate: %d\n", dev);
 
+    /*
+     * We didn't construct this VBD by reading a partition table. This
+     * function can only do bad things to us.
+     */
+    if ( capacity == 0 )
+        return -EINVAL;
+
     spin_lock_irqsave(&io_request_lock, flags);
     if ( disk->usage > 1 )
     {
@@ -212,27 +230,9 @@ int xenolinux_block_revalidate(kdev_t dev)
         gd->part[MINOR(dev+i)].nr_sects = 0;
     }
 
-#if 0
-    /* VBDs can change under our feet. Check if that has happened. */
-    if ( MAJOR(dev) == XLVIRT_MAJOR )
-    {
-        xen_disk_info_t *xdi = kmalloc(sizeof(*xdi), GFP_KERNEL);
-        if ( xdi != NULL )
-        {
-            memset(xdi, 0, sizeof(*xdi));
-            xenolinux_control_msg(XEN_BLOCK_PROBE, 
-                                  (char *)xdi, sizeof(*xdi));
-            for ( i = 0; i < xdi->count; i++ )
-                if ( IS_VIRTUAL_XENDEV(xdi->disks[i].device) &&
-                     ((xdi->disks[i].device & XENDEV_IDX_MASK) == disk_nr) )
-                    ((xl_disk_t *)gd->real_devices)[disk_nr].capacity =
-                        xdi->disks[i].capacity;
-            kfree(xdi);
-        }
-    }
-#endif
+    /* XXX Should perhaps revalidate VBDs here */
 
-    grok_partitions(gd, disk_nr, gd->nr_real, disk->capacity);
+    grok_partitions(gd, disk_nr, gd->nr_real, capacity);
 
     return 0;
 }
@@ -271,14 +271,12 @@ static int hypervisor_request(unsigned long   id,
 
     case XEN_BLOCK_READ:
     case XEN_BLOCK_WRITE:
+        gd = get_gendisk(device); 
 
-       /* Get the appropriate gendisk */
-       gd = xldev_to_gendisk(device); 
-
-       /* Update the sector_number we'll pass down as appropriate; note 
-          that we could sanity check that resulting sector will be in 
-          this partition, but this will happen in xen anyhow */
-       sector_number += gd->part[MINOR(device)].start_sect;
+        /* Update the sector_number we'll pass down as appropriate; note 
+           that we could sanity check that resulting sector will be in 
+           this partition, but this will happen in xen anyhow */
+        sector_number += gd->part[MINOR(device)].start_sect;
 
         if ( (sg_operation == operation) &&
              (sg_dev == device) &&
@@ -339,9 +337,9 @@ void do_xlblk_request(request_queue_t *rq)
 
     while ( !rq->plugged && !list_empty(&rq->queue_head))
     {
-       if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) 
-           goto out;
-               
+        if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) 
+            goto out;
+  
         DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
                 req, req->cmd, req->sector,
                 req->current_nr_sectors, req->nr_sectors, req->bh);
@@ -351,11 +349,11 @@ void do_xlblk_request(request_queue_t *rq)
         if ((rw != READ) && (rw != WRITE))
             panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
 
-       req->errors = 0;
+        req->errors = 0;
 
         bh = req->bh;
         while ( bh != NULL )
-       {
+        {
             next_bh = bh->b_reqnext;
             bh->b_reqnext = NULL;
 
@@ -364,12 +362,12 @@ void do_xlblk_request(request_queue_t *rq)
                 (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
                 bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
 
-           if(full) { 
+            if(full) { 
 
-               bh->b_reqnext = next_bh;
-               pending_queues[nr_pending++] = rq;
-               if ( nr_pending >= MAX_PENDING ) BUG();
-               goto out; 
+                bh->b_reqnext = next_bh;
+                pending_queues[nr_pending++] = rq;
+                if ( nr_pending >= MAX_PENDING ) BUG();
+                goto out; 
 
             }
 
@@ -430,15 +428,15 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
     if ( state == STATE_CLOSED )
         return;
     
-    spin_lock_irqsave(&io_request_lock, flags);            
+    spin_lock_irqsave(&io_request_lock, flags);     
 
     for ( i  = resp_cons;
-         i != blk_ring->resp_prod;
-         i  = BLK_RING_INC(i) )
+          i != blk_ring->resp_prod;
+          i  = BLK_RING_INC(i) )
     {
-       blk_ring_resp_entry_t *bret = &blk_ring->ring[i].resp;
-       switch (bret->operation)
-       {
+        blk_ring_resp_entry_t *bret = &blk_ring->ring[i].resp;
+        switch (bret->operation)
+        {
         case XEN_BLOCK_READ:
         case XEN_BLOCK_WRITE:
             if ( bret->status )
@@ -452,11 +450,11 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
                 bh->b_reqnext = NULL;
                 bh->b_end_io(bh, !bret->status);
             }
-           break;
-           
+            break;
+     
         default:
             BUG();
-       }
+        }
     }
     
     resp_cons = i;
@@ -501,8 +499,8 @@ int __init xlblk_init(void)
                         SA_SAMPLE_RANDOM, "blkdev", NULL);
     if ( error )
     {
-       printk(KERN_ALERT "Could not allocate receive interrupt\n");
-       goto fail;
+        printk(KERN_ALERT "Could not allocate receive interrupt\n");
+        goto fail;
     }
 
     /* Setup our [empty] disk information structure */
index 8fcaa59383e2f4f3694768e2f150dda1e90cee8d..c4cd7ec44e37ea63f84bf4a2807ac622eb87d6c4 100644 (file)
@@ -47,7 +47,6 @@
  */
 typedef struct xl_disk {
     int usage;
-    unsigned long capacity;
 } xl_disk_t;
 
 /* Generic layer. */
@@ -55,7 +54,7 @@ extern int xenolinux_control_msg(int operration, char *buffer, int size);
 extern int xenolinux_block_open(struct inode *inode, struct file *filep);
 extern int xenolinux_block_release(struct inode *inode, struct file *filep);
 extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
-                                unsigned command, unsigned long argument);
+                                 unsigned command, unsigned long argument);
 extern int xenolinux_block_check(kdev_t dev);
 extern int xenolinux_block_revalidate(kdev_t dev);
 extern void do_xlblk_request (request_queue_t *rq); 
@@ -64,6 +63,5 @@ extern void do_xlblk_request (request_queue_t *rq);
 /* Virtual block-device subsystem. */
 extern int  xlvbd_init(xen_disk_info_t *xdi);
 extern void xlvbd_cleanup(void); 
-extern struct gendisk *xldev_to_gendisk(kdev_t xldev);
 
 #endif /* __XL_BLOCK_H__ */
index 386162e9f30170d42f4255c5abb52ee9de58513c..2b65705083444467e285892355bbaad94122754f 100644 (file)
@@ -6,16 +6,9 @@
  */
 
 #include "xl_block.h"
-
-// #define MAJOR_NR XLVIRT_MAJOR
 #include <linux/blk.h>
 
-/* Copied from linux/ide.h */
-typedef unsigned char byte; 
-
-#define XLVBD_MAX_MAJORS  64  /* total number of vbds we support */
-
-struct gendisk *xlvbd_gendisk[XLVBD_MAX_MAJORS] = { NULL };
+#define GENHD_FL_XENO     2
 
 /* For convenience we distinguish between ide, scsi and 'other' (i.e. 
 ** potentially combinations of the two) in the naming scheme and in a 
@@ -29,7 +22,6 @@ struct gendisk *xlvbd_gendisk[XLVBD_MAX_MAJORS] = { NULL };
 #define XLSCSI_DEVS_PER_MAJOR 16
 #define XLVBD_DEVS_PER_MAJOR  16
 
-
 #define XLIDE_PARTN_SHIFT  6    /* amount to shift minor to get 'real' minor */
 #define XLIDE_MAX_PART    (1 << XLIDE_PARTN_SHIFT)     /* minors per ide vbd */
 
@@ -39,7 +31,6 @@ struct gendisk *xlvbd_gendisk[XLVBD_MAX_MAJORS] = { NULL };
 #define XLVBD_PARTN_SHIFT  6    /* amount to shift minor to get 'real' minor */
 #define XLVBD_MAX_PART    (1 << XLVBD_PARTN_SHIFT) /* minors per 'other' vbd */
 
-
 /* the below are for the use of the generic drivers/block/ll_rw_block.c code */
 static int xlide_blksize_size[256];
 static int xlide_hardsect_size[256];
@@ -51,7 +42,6 @@ static int xlvbd_blksize_size[256];
 static int xlvbd_hardsect_size[256];
 static int xlvbd_max_sectors[256];
 
-
 static struct block_device_operations xlvbd_block_fops = 
 {
     open:               xenolinux_block_open,
@@ -61,290 +51,262 @@ static struct block_device_operations xlvbd_block_fops =
     revalidate:         xenolinux_block_revalidate,
 };
 
-
-typedef unsigned char bool; 
-
-/* 
-** Set up all the linux device goop for the virtual block devices (vbd's)
-** that xen tells us about. Note that although from xen's pov VBDs are 
-** addressed simply an opaque 16-bit device number, the domain creation 
-** tools conventionally allocate these numbers to correspond to those 
-** used by 'real' linux -- this is just for convenience as it means e.g. 
-** that the same /etc/fstab can be used when booting with or without xen.
-*/
+/*
+ * Set up all the linux device goop for the virtual block devices (vbd's) that 
+ * xen tells us about. Note that although from xen's pov VBDs are addressed 
+ * simply an opaque 16-bit device number, the domain creation tools 
+ * conventionally allocate these numbers to correspond to those used by 'real' 
+ * linux -- this is just for convenience as it means e.g. that the same 
+ * /etc/fstab can be used when booting with or without xen.
+ */
 int __init xlvbd_init(xen_disk_info_t *xdi)
 {
     int i, result, max_part; 
     struct gendisk *gd = NULL;
     kdev_t device; 
     unsigned short major, minor, partno; 
-    bool is_ide, is_scsi; 
+    int is_ide, is_scsi; 
     char *major_name; 
     unsigned char buf[64]; 
-    int majors[256]; 
 
     SET_MODULE_OWNER(&xlvbd_block_fops);
 
     /* Initialize the global arrays. */
-    for (i = 0; i < 256; i++
+    for ( i = 0; i < 256; i++ 
     {
-       /* from the generic ide code (drivers/ide/ide-probe.c, etc) */
-       xlide_blksize_size[i]  = 1024;
-       xlide_hardsect_size[i] = 512;
-       xlide_max_sectors[i]   = 128;  /* 'hwif->rqsize' if we knew it */
-
-       /* from the generic scsi disk code (drivers/scsi/sd.c) */
-       xlscsi_blksize_size[i]  = 1024; //XXX 512;
-       xlscsi_hardsect_size[i] = 512;
-       xlscsi_max_sectors[i]   = 128*8; //XXX 128;
-
-       /* we don't really know what to set these too since it depends */
-       xlvbd_blksize_size[i]  = 512;
-       xlvbd_hardsect_size[i] = 512;
-       xlvbd_max_sectors[i]   = 128;
+        /* from the generic ide code (drivers/ide/ide-probe.c, etc) */
+        xlide_blksize_size[i]  = 1024;
+        xlide_hardsect_size[i] = 512;
+        xlide_max_sectors[i]   = 128;  /* 'hwif->rqsize' if we knew it */
+
+        /* from the generic scsi disk code (drivers/scsi/sd.c) */
+        xlscsi_blksize_size[i]  = 1024; /* XXX 512; */
+        xlscsi_hardsect_size[i] = 512;
+        xlscsi_max_sectors[i]   = 128*8; /* XXX 128; */
+
+        /* we don't really know what to set these too since it depends */
+        xlvbd_blksize_size[i]  = 512;
+        xlvbd_hardsect_size[i] = 512;
+        xlvbd_max_sectors[i]   = 128;
     }
 
-
-    /* keep track of which majors we've seen so far */
-    for (i = 0; i < 256; i++) 
-       majors[i] = 0; 
-
-    /* 
-    ** We need to loop through each major device we've been told about and: 
-    ** a) register the appropriate blkdev 
-    ** b) setup the indexed-by-major global arrays (blk_size[], 
-    **    blksize_size[], hardsect_size[], max_sectors[], read_ahead[]) 
-    ** c) setup the block queue + make it sensible
-    ** d) create an appropriate gendisk structure, and 
-    ** e) register the gendisk 
-    */
-    for (i = 0; i < xdi->count; i++)
+    /*
+     * We need to loop through each major device we've been told about and: 
+     * a) register the appropriate blkdev 
+     * b) setup the indexed-by-major global arrays (blk_size[], 
+     *    blksize_size[], hardsect_size[], max_sectors[], read_ahead[]) 
+     * c) setup the block queue + make it sensible
+     * d) create an appropriate gendisk structure, and 
+     * e) register the gendisk 
+     */
+    for ( i = 0; i < xdi->count; i++ )
     {
-       device = xdi->disks[i].device;
-       major  = MAJOR(device); 
-       minor  = MINOR(device);
-       is_ide = IDE_DISK_MAJOR(major);  /* is this an ide device? */
-       is_scsi= SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
-       
-       if(is_ide) { 
-           major_name = XLIDE_MAJOR_NAME; 
-           max_part   = XLIDE_MAX_PART;
-       } else if(is_scsi) { 
-           major_name = XLSCSI_MAJOR_NAME;
-           max_part   = XLSCSI_MAX_PART;
-       } else { 
-           major_name = XLVBD_MAJOR_NAME;
-           max_part   = XLVBD_MAX_PART;
-       }
-
-       /* 
-       ** XXX SMH: conventionally we assume a minor device if the 
-       ** corresponding linux device number would be a minor device; 
-       ** minor devices require slightly different handling than 
-       ** 'full' devices (e.g. in terms of partition table handling). 
-       */
-       partno = minor & (max_part - 1); 
-
-       if(!majors[major]) {
-
-           result = register_blkdev(major, major_name, &xlvbd_block_fops);
-           if (result < 0) {
-               printk(KERN_ALERT "XL VBD: can't get major %d\n", major);
-               continue; 
-           }
-
-           blk_size[major]      = NULL;
-           if(is_ide) { 
-               blksize_size[major]  = xlide_blksize_size;
-               hardsect_size[major] = xlide_hardsect_size;
-               max_sectors[major]   = xlide_max_sectors;
-               read_ahead[major]    = 8; // from drivers/ide/ide-probe.c
-           } else if(is_scsi) { 
-               blksize_size[major]  = xlscsi_blksize_size;
-               hardsect_size[major] = xlscsi_hardsect_size;
-               max_sectors[major]   = xlscsi_max_sectors;
-               read_ahead[major]    = 0; // XXX 8; -- guessing 
-           } else { 
-               blksize_size[major]  = xlvbd_blksize_size;
-               hardsect_size[major] = xlvbd_hardsect_size;
-               max_sectors[major]   = xlvbd_max_sectors;
-               read_ahead[major]    = 8;
-           }
-       
-           blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
-       
-           /*
-            * Turn off barking 'headactive' mode. We dequeue buffer heads as
-            * soon as we pass them down to Xen.
-            */
-           blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
-
-           /* Construct an appropriate gendisk structure. */
-           gd             = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
-           gd->major      = major;
-           gd->major_name = major_name; 
-           
-           gd->max_p      = max_part; 
-           if(is_ide) { 
-               gd->minor_shift  = XLIDE_PARTN_SHIFT; 
-               gd->nr_real      = XLIDE_DEVS_PER_MAJOR; 
-           } else if(is_scsi) { 
-               gd->minor_shift  = XLSCSI_PARTN_SHIFT; 
-               gd->nr_real      = XLSCSI_DEVS_PER_MAJOR; 
-           } else { 
-               gd->minor_shift  = XLVBD_PARTN_SHIFT; 
-               gd->nr_real      = XLVBD_DEVS_PER_MAJOR; 
-           }
-
-           /* 
-           ** The sizes[] and part[] arrays hold the sizes and other 
-           ** information about every partition with this 'major' (i.e. 
-           ** every disk sharing the 8 bit prefix * max partns per disk) 
-           */
-           gd->sizes = kmalloc(max_part*gd->nr_real*sizeof(int), GFP_KERNEL);
-           gd->part  = kmalloc(max_part*gd->nr_real*sizeof(struct hd_struct), 
-                                    GFP_KERNEL);
-           memset(gd->sizes, 0, max_part * gd->nr_real * sizeof(int));
-           memset(gd->part,  0, max_part * gd->nr_real 
-                  * sizeof(struct hd_struct));
-
-
-           gd->real_devices = kmalloc(gd->nr_real * sizeof(xl_disk_t), 
-                                      GFP_KERNEL);
-           memset(gd->real_devices, 0, gd->nr_real * sizeof(xl_disk_t));
-
-           gd->next   = NULL;            
-           gd->fops   = &xlvbd_block_fops;
-
-           gd->de_arr = kmalloc(gd->nr_real * sizeof(*gd->de_arr), 
-                                GFP_KERNEL);
-           gd->flags  = kmalloc(gd->nr_real * sizeof(*gd->flags), GFP_KERNEL);
-           
-           memset(gd->de_arr, 0, gd->nr_real * sizeof(*gd->de_arr));
-           memset(gd->flags, 0, gd->nr_real *  sizeof(*gd->flags));
-
-           /* 
-           ** Keep track of gendisk both locally and in the global array. 
-           ** XXX SMH: can probably do without local copy -- FIXME later 
-           */
-           xlvbd_gendisk[i] = gd;
-           add_gendisk(gd);
-
-           /* XXX SMH: not clear on what 'real_devices' is indexed by; 
-              hence using unit number for now but in old code was 'disk' aka 
-              sequence number assigned by xen during probe = barfle? */
-           ((xl_disk_t *)gd->real_devices)[minor>>gd->minor_shift].capacity =
-           xdi->disks[i].capacity;
-
-           
-           /* remember that we've done this major */
-           majors[major] = 1; 
-       } else 
-           /* Continue the setup of this gendisk */
-           gd = get_gendisk(device); 
-
-       if(XD_READONLY(xdi->disks[i].info)) 
-           set_device_ro(device, 1); 
-
-       if(partno) { 
-
-           /* Need to skankily setup 'partition' information */
-           gd->part[partno].start_sect = 0; 
-           gd->part[partno].nr_sects   = xdi->disks[i].capacity; 
-           gd->sizes[partno]           = xdi->disks[i].capacity; 
-
-       } else { 
-
-           /* Some final fix-ups depending on the device type */
-           switch (XD_TYPE(xdi->disks[i].info)) 
-           { 
-
-           case XD_TYPE_CDROM:
-           case XD_TYPE_FLOPPY: 
-           case XD_TYPE_TAPE:
-               gd->flags[minor >> gd->minor_shift] = GENHD_FL_REMOVABLE; 
-               printk(KERN_ALERT 
-                      "Skipping partition check on %s /dev/%s\n", 
-                      XD_TYPE(xdi->disks[i].info)==XD_TYPE_CDROM ? "cdrom" : 
-                      (XD_TYPE(xdi->disks[i].info)==XD_TYPE_TAPE ? "tape" : 
-                       "floppy"), disk_name(gd, MINOR(device), buf)); 
-               break; 
-               
-           case XD_TYPE_DISK: 
-               register_disk(gd, device, gd->nr_real, &xlvbd_block_fops, 
-                             xdi->disks[i].capacity);
-               break; 
-               
-           default: 
-               printk(KERN_ALERT "XenoLinux: unknown device type %d\n", 
-                      XD_TYPE(xdi->disks[i].info)); 
-               break; 
-           }
-
-       }
-           
-       printk(KERN_ALERT "XenoLinux Virtual Block Device Driver "
-              "installed [device: %04x]\n", device);
+        device = xdi->disks[i].device;
+        major  = MAJOR(device); 
+        minor  = MINOR(device);
+        is_ide = IDE_DISK_MAJOR(major);  /* is this an ide device? */
+        is_scsi= SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
+
+        if ( is_ide )
+        { 
+            major_name = XLIDE_MAJOR_NAME; 
+            max_part   = XLIDE_MAX_PART;
+        }
+        else if ( is_scsi )
+        { 
+            major_name = XLSCSI_MAJOR_NAME;
+            max_part   = XLSCSI_MAX_PART;
+        }
+        else
+        { 
+            major_name = XLVBD_MAJOR_NAME;
+            max_part   = XLVBD_MAX_PART;
+        }
+
+        partno = minor & (max_part - 1); 
+
+        if ( (gd = get_gendisk(device)) == NULL )
+        {
+            result = register_blkdev(major, major_name, &xlvbd_block_fops);
+            if ( result < 0 )
+            {
+                printk(KERN_ALERT "XL VBD: can't get major %d\n", major);
+                continue; 
+            }
+
+            if( is_ide )
+            { 
+                blksize_size[major]  = xlide_blksize_size;
+                hardsect_size[major] = xlide_hardsect_size;
+                max_sectors[major]   = xlide_max_sectors;
+                read_ahead[major]    = 8; /* from drivers/ide/ide-probe.c */
+            } 
+            else if ( is_scsi )
+            { 
+                blksize_size[major]  = xlscsi_blksize_size;
+                hardsect_size[major] = xlscsi_hardsect_size;
+                max_sectors[major]   = xlscsi_max_sectors;
+                read_ahead[major]    = 0; /* XXX 8; -- guessing */
+            }
+            else
+            { 
+                blksize_size[major]  = xlvbd_blksize_size;
+                hardsect_size[major] = xlvbd_hardsect_size;
+                max_sectors[major]   = xlvbd_max_sectors;
+                read_ahead[major]    = 8;
+            }
+
+            blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
+
+            /*
+             * Turn off barking 'headactive' mode. We dequeue buffer heads as
+             * soon as we pass them down to Xen.
+             */
+            blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
+
+            /* Construct an appropriate gendisk structure. */
+            gd             = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+            gd->major      = major;
+            gd->major_name = major_name; 
+    
+            gd->max_p      = max_part; 
+            if ( is_ide )
+            { 
+                gd->minor_shift  = XLIDE_PARTN_SHIFT; 
+                gd->nr_real      = XLIDE_DEVS_PER_MAJOR; 
+            } 
+            else if ( is_scsi )
+            { 
+                gd->minor_shift  = XLSCSI_PARTN_SHIFT; 
+                gd->nr_real      = XLSCSI_DEVS_PER_MAJOR; 
+            }
+            else
+            { 
+                gd->minor_shift  = XLVBD_PARTN_SHIFT; 
+                gd->nr_real      = XLVBD_DEVS_PER_MAJOR; 
+            }
+
+            /* 
+            ** The sizes[] and part[] arrays hold the sizes and other 
+            ** information about every partition with this 'major' (i.e. 
+            ** every disk sharing the 8 bit prefix * max partns per disk) 
+            */
+            gd->sizes = kmalloc(max_part*gd->nr_real*sizeof(int), GFP_KERNEL);
+            gd->part  = kmalloc(max_part*gd->nr_real*sizeof(struct hd_struct), 
+                                GFP_KERNEL);
+            memset(gd->sizes, 0, max_part * gd->nr_real * sizeof(int));
+            memset(gd->part,  0, max_part * gd->nr_real 
+                   * sizeof(struct hd_struct));
+
+
+            gd->real_devices = kmalloc(gd->nr_real * sizeof(xl_disk_t), 
+                                       GFP_KERNEL);
+            memset(gd->real_devices, 0, gd->nr_real * sizeof(xl_disk_t));
+
+            gd->next   = NULL;            
+            gd->fops   = &xlvbd_block_fops;
+
+            gd->de_arr = kmalloc(gd->nr_real * sizeof(*gd->de_arr), 
+                                 GFP_KERNEL);
+            gd->flags  = kmalloc(gd->nr_real * sizeof(*gd->flags), GFP_KERNEL);
+    
+            memset(gd->de_arr, 0, gd->nr_real * sizeof(*gd->de_arr));
+            memset(gd->flags, 0, gd->nr_real *  sizeof(*gd->flags));
+
+            add_gendisk(gd);
+
+            blk_size[major] = gd->sizes;
+        }
+
+        if ( XD_READONLY(xdi->disks[i].info) )
+            set_device_ro(device, 1); 
+
+        gd->flags[minor >> gd->minor_shift] |= GENHD_FL_XENO;
+        
+        if ( partno != 0 )
+        { 
+            /* Need to skankily setup 'partition' information */
+            gd->part[partno].start_sect = 0; 
+            gd->part[partno].nr_sects   = xdi->disks[i].capacity; 
+            gd->sizes[partno]           = xdi->disks[i].capacity; 
+        }
+        else
+        { 
+            /* Some final fix-ups depending on the device type */
+            switch ( XD_TYPE(xdi->disks[i].info) )
+            { 
+            case XD_TYPE_CDROM:
+            case XD_TYPE_FLOPPY: 
+            case XD_TYPE_TAPE:
+                gd->part[minor].nr_sects = xdi->disks[i].capacity;
+                gd->sizes[minor] = xdi->disks[i].capacity>>(BLOCK_SIZE_BITS-9);
+                gd->flags[minor >> gd->minor_shift] |= GENHD_FL_REMOVABLE; 
+                printk(KERN_ALERT 
+                       "Skipping partition check on %s /dev/%s\n", 
+                       XD_TYPE(xdi->disks[i].info)==XD_TYPE_CDROM ? "cdrom" : 
+                       (XD_TYPE(xdi->disks[i].info)==XD_TYPE_TAPE ? "tape" : 
+                        "floppy"), disk_name(gd, MINOR(device), buf)); 
+                break; 
+
+            case XD_TYPE_DISK: 
+                register_disk(gd, device, gd->nr_real, &xlvbd_block_fops, 
+                              xdi->disks[i].capacity);
+                break; 
+
+            default: 
+                printk(KERN_ALERT "XenoLinux: unknown device type %d\n", 
+                       XD_TYPE(xdi->disks[i].info)); 
+                break; 
+            }
+        }
+    
+        printk(KERN_ALERT "XenoLinux Virtual Block Device Driver "
+               "installed [device: %04x]\n", device);
     }
 
     return 0;
 }
 
-/* 
-** XXX SMH: crappy linear scan routine to map from a device number bac k
-** to the relevant gendisk; could be made better if and when it becomes 
-** an issue but for now we expect success within a few loop iterations. 
-*/
-struct gendisk *xldev_to_gendisk(kdev_t xldev)
-{
-    int i; 
-    short major = MAJOR(xldev); 
-    
-    for(i = 0; i < XLVBD_MAX_MAJORS; i++) { 
-       if(xlvbd_gendisk[i]->major == major)
-           return xlvbd_gendisk[i]; 
-    }
-    
-    /* didn't find it -- death */
-    BUG();
-    return NULL; 
-}
-
 void xlvbd_cleanup(void)
 {
-    bool is_ide, is_scsi; 
+    int is_ide, is_scsi, i; 
     struct gendisk *gd; 
     char *major_name; 
     int major; 
 
-    for(major = 0; major < XLVBD_MAX_MAJORS; major++) { 
-
-       if(!(gd = xlvbd_gendisk[major]))
-           continue; 
-
-       is_ide = IDE_DISK_MAJOR(major);  /* is this an ide device? */
-       is_scsi= SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
-
-       blk_cleanup_queue(BLK_DEFAULT_QUEUE(major)); 
-       
-       if(is_ide) { 
-           major_name = XLIDE_MAJOR_NAME; 
-       } else if(is_scsi) { 
-           major_name = XLSCSI_MAJOR_NAME;
-       } else { 
-           major_name = XLVBD_MAJOR_NAME;
-       }
-
-       if (unregister_blkdev(major, major_name) != 0) 
-           printk(KERN_ALERT "XenoLinux Virtual Block Device Driver:"
-                  "major device %04x uninstalled w/ errors\n", major); 
-
+    for ( major = 0; major < MAX_BLKDEV; major++ )
+    {
+        if ( (gd = get_gendisk(MKDEV(major, 0))) == NULL )
+            continue; 
+
+        /*
+         * If this is a 'Xeno' blkdev then at least one unit will have the Xeno
+         * flag set.
+         */
+        for ( i = 0; i < gd->nr_real; i++ )
+            if ( gd->flags[i] & GENHD_FL_XENO )
+                break;
+        if ( i == gd->nr_real )
+            continue;
+        
+        is_ide  = IDE_DISK_MAJOR(major);  /* is this an ide device? */
+        is_scsi = SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
+
+        blk_cleanup_queue(BLK_DEFAULT_QUEUE(major)); 
+
+        if ( is_ide ) 
+            major_name = XLIDE_MAJOR_NAME; 
+        else if ( is_scsi )
+            major_name = XLSCSI_MAJOR_NAME;
+        else 
+            major_name = XLVBD_MAJOR_NAME;
+
+        if ( unregister_blkdev(major, major_name) != 0 ) 
+            printk(KERN_ALERT "XenoLinux Virtual Block Device Driver:"
+                   "major device %04x uninstalled w/ errors\n", major); 
     }
-
-    return; 
 }
 
-
 #ifdef MODULE
 module_init(xlvbd_init);
 module_exit(xlvbd_cleanup);